<template>
  <el-dialog :model-value="visible" @update:model-value="val => emit('update:visible', val)" title="裁剪头像"
    class="advanced-cropper" width="480px">
    <template #header>
      <div class="text-lg font-semibold text-gray-800">裁剪头像</div>
    </template>
    <div class="h-[320px] bg-gray-50 rounded-lg shadow-sm p-1.5 relative flex items-center justify-center">
      <img ref="cropperRef" :src="src" class="block h-full w-full object-contain rounded-[6px]" />
      <!-- 圆形实时预览 -->
      <div class="avatar-preview absolute right-4 top-4 flex flex-col items-center">
        <span class="text-xs text-gray-500 mb-1">实时预览</span>
        <div class="preview-circle" ref="previewRef"></div>
      </div>
    </div>
    <template #footer>
      <div class="flex justify-end gap-3">
        <el-button @click="emit('update:visible', false)" class="!text-gray-600 !border-none hover:!bg-gray-100">
          取 消
        </el-button>
        <el-button type="primary" @click="getCroppedImage"
          class="!bg-indigo-500 hover:!bg-indigo-600 !border-none !shadow-sm">
          确 定
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, watch, nextTick, onMounted } from 'vue'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'

const props = defineProps({
  src: String,
  visible: Boolean,
  aspectRatio: { type: Number, default: 1 }, // 头像1:1
  watermarkText: { type: String, default: "www.eleventhy.cn" }
})

const emit = defineEmits(['update:visible', 'cropped'])

const cropperRef = ref<HTMLImageElement | null>(null)
const previewRef = ref<HTMLDivElement | null>(null)
let cropperInstance: Cropper | null = null

// 实时预览
const updatePreview = () => {
  if (!cropperInstance || !previewRef.value) return
  const canvas = cropperInstance.getCroppedCanvas({ width: 100, height: 100 })
  previewRef.value.innerHTML = ''
  const img = document.createElement('img')
  img.src = canvas.toDataURL('image/png')
  img.style.width = '100%'
  img.style.height = '100%'
  img.style.borderRadius = '50%'
  previewRef.value.appendChild(img)
}

watch(() => props.visible, (newVal) => {
  if (newVal) {
    nextTick(() => {
      if (cropperRef.value) {
        cropperInstance = new Cropper(cropperRef.value, {
          aspectRatio: props.aspectRatio,
          viewMode: 2,
          dragMode: 'crop',
          autoCropArea: 1,
          restore: false,
          guides: true,
          highlight: false,
          cropBoxMovable: true,
          cropBoxResizable: true,
          minCropBoxWidth: 100,
          minCropBoxHeight: 100,
          ready() {
            updatePreview()
          },
          crop() {
            updatePreview()
          }
        })
      }
    })
  } else {
    if (cropperInstance) {
      cropperInstance.destroy()
      cropperInstance = null
    }
  }
})

onMounted(() => {
  if (props.visible && cropperRef.value) {
    cropperInstance = new Cropper(cropperRef.value, {
      aspectRatio: props.aspectRatio,
      viewMode: 2,
      dragMode: 'crop',
      autoCropArea: 1,
      restore: false,
      guides: true,
      highlight: false,
      cropBoxMovable: true,
      cropBoxResizable: true,
      minCropBoxWidth: 100,
      minCropBoxHeight: 100,
      ready() {
        updatePreview()
      },
      crop() {
        updatePreview()
      }
    })
  }
})

const getCroppedImage = () => {
  if (!cropperInstance) return
  const canvas = cropperInstance.getCroppedCanvas({ width: 256, height: 256, imageSmoothingQuality: 'high' })
  const watermarkCanvas = document.createElement('canvas')
  const ctx = watermarkCanvas.getContext('2d')!
  watermarkCanvas.width = canvas.width
  watermarkCanvas.height = canvas.height
  ctx.imageSmoothingEnabled = true
  ctx.imageSmoothingQuality = 'high'
  ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height)
  // 水印
  const fontSize = Math.min(canvas.width * 0.08, 32)
  ctx.font = `italic ${fontSize}px Arial`
  ctx.fillStyle = 'rgba(255,255,255,0.6)'
  ctx.textAlign = 'right'
  ctx.textBaseline = 'bottom'
  ctx.shadowColor = 'rgba(0,0,0,0.3)'
  ctx.shadowOffsetX = 2
  ctx.shadowOffsetY = 2
  ctx.shadowBlur = 3
  const padding = fontSize * 0.5
  const x = canvas.width - padding
  const y = canvas.height - padding
  ctx.fillText(props.watermarkText, x, y)
  watermarkCanvas.toBlob(blob => {
    emit('cropped', blob)
    emit('update:visible', false)
  }, 'image/png', 0.95)
}
</script>

<style scoped>
.advanced-cropper :deep(.el-dialog) {
  border-radius: 16px;
}
.avatar-preview {
  width: 110px;
  height: 120px;
  z-index: 10;
  user-select: none;
}
.preview-circle {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>
